package core.communication;


import core.exception.LoadContextException;
import core.exception.LoadMailException;
import core.exception.SendMailException;
import core.model.Game;
import core.model.mail.Context;
import core.model.mail.Message;
import core.util.Parser;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;

public class ServerConnectorFacade {

    private static String SEND_ORDER_HEADER_TEMPLATE = "#order {0} {1} turn {2}";
    private static final String FOOTER = "#end";

    private Game game;
    private ServerConnectorService connector = new ServerConnectorService();
    private Parser parser = new Parser();

    public ServerConnectorFacade(Game game) {
        this.game = game;
    }

/*
    private ReportService reportService = new ReportService();
*/

    public void loadGameList() throws UnknownHostException {
        try {
            Document response = connector.loadGameList();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

    }

/*
    public Report loadReport() {
        Context context = loadContext();
        return reportService.loadReport(context.getTurn());
    }
*/


/*
    public Report loadReport(int turn) {
        return reportService.loadReport(turn);
    }
*/

    public List<String> loadRaces(String game) throws LoadMailException {

        Document response = null;

        try {
            response = connector.races(game);
            String result = parser.parseResponseError(response);
            if (result != null && !StringUtils.EMPTY.equals(result)) {
                throw new LoadMailException(result);
            }

        } catch (IOException e) {
            throw new LoadMailException(e);
        } catch (SAXException e) {
            throw new LoadMailException(e);
        } catch (ParserConfigurationException e) {
            throw new LoadMailException(e);
        }


        return parser.parseRaces(response);
    }

    public Context loadMessages() throws LoadContextException, LoadMailException {
        Context context = loadContext(game.getParty(), game.getRace(), game.getPassword());

        // skip loading messages if nothing to load.
        if ((context.getBroadcasts() == null || context.getBroadcasts().isEmpty()) &&
                (context.getPrivates() == null || context.getPrivates().isEmpty())) {
            return context;
        }

        String fileIds = buildFileIds(context);

        Document response = null;
        try {
            response = connector.loadMessages(game.getParty(), game.getRace(), game.getPassword(), fileIds);
            String result = parser.parseResponseError(response);
            if (result != null && !StringUtils.EMPTY.equals(result)) {
                throw new LoadMailException(result);
            }

        } catch (IOException e) {
            throw new LoadMailException(e);
        } catch (SAXException e) {
            throw new LoadMailException(e);
        } catch (ParserConfigurationException e) {
            throw new LoadMailException(e);
        }

        Map<String, String> result = parser.parseMessages(response);

        fillBodies(context.getPrivates(), result);
        fillBodies(context.getBroadcasts(), result);

        return context;
    }

    private void fillBodies(List<Message> messages, Map<String, String> result) {
        for (Message message : messages) {
            String fileId = message.getFile();
            if (result.containsKey(fileId)) {
                message.setBody(result.get(fileId));
            }
        }
    }

    private String buildFileIds(Context context) {

        StringBuffer fileIds = new StringBuffer();

        List<Message> privates = context.getPrivates();

        for (Message message : privates) {
            if (fileIds.length() > 0) {
                fileIds.append("\n");
            }
            fileIds.append(message.getFile());
        }

        List<Message> broadcasts = context.getBroadcasts();

        for (Message message : broadcasts) {
            if (fileIds.length() > 0) {
                fileIds.append("\n");
            }
            fileIds.append(message.getFile());
        }

        return fileIds.toString();
    }

/*
    public String sendOrder(String game, int turn, String race, String password, LinkedList<String> commands) {
        String header = MessageFormat.format(SEND_ORDER_HEADER_TEMPLATE, game, password, turn);

        StringBuffer orderBody = new StringBuffer();
        orderBody.append(header).append("\r\n");

        for (String command : commands) {
            orderBody.append(command).append("\r\n");
        }

        orderBody.append(FOOTER).append("\r\n");

        Document response = connector.sendOrder(game, turn, race, password, orderBody.toString());

        return parser.parseResponseError(response);

    }
*/

    public Context loadContext(String party, String race, String password) throws LoadContextException {
        Document response = null;

        try {
            response = connector.loadContext(party, race, password);
            String result = parser.parseResponseError(response);
            if (result != null && !StringUtils.EMPTY.equals(result)) {
                throw new LoadContextException(result);
            }
        } catch (IOException e) {
            throw new LoadContextException(e);
        } catch (SAXException e) {
            throw new LoadContextException(e);
        } catch (ParserConfigurationException e) {
            throw new LoadContextException(e);
        }

        if (response == null) {
            return new Context();
        }

        return parser.parseContext(response);
    }

    public void sendMessage(String to, String text) throws SendMailException {
        Document response = null;
        try {
            response = connector.sendMessage("mail", game.getParty(), game.getRace(), game.getPassword(), to, text);
            String result = parser.parseResponseError(response);
            if (result != null && !StringUtils.EMPTY.equals(result)) {
                throw new SendMailException(result);
            }
        } catch (IOException e) {
            throw new SendMailException(e);
        } catch (SAXException e) {
            throw new SendMailException(e);
        } catch (ParserConfigurationException e) {
            throw new SendMailException(e);
        }
    }

    public void sendBroadcast(String text) throws SendMailException {
        Document response = null;
        try {
            response = connector.sendMessage("broadcast", game.getParty(), game.getRace(), game.getPassword(), null, text);
            String result = parser.parseResponseError(response);
            if (result != null && !StringUtils.EMPTY.equals(result)) {
                throw new SendMailException(result);
            }
        } catch (IOException e) {
            throw new SendMailException(e);
        } catch (SAXException e) {
            throw new SendMailException(e);
        } catch (ParserConfigurationException e) {
            throw new SendMailException(e);
        }
    }
}